﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.IO;
using System.Windows.Resources;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace SandwichFlow
{
  public class SandwichFlowViewModel
  {
    public List<Sandwich> Sandwiches { get; set; }

    public List<Keyword> Keywords { get; set; }

    public SandwichFlowViewModel()
    {
      LoadData();
    }

    private void LoadData()
    {
      string path = "/SandwichFlow;component/sandwiches.xml";
      Uri uri = new Uri(path, UriKind.Relative);
      StreamResourceInfo sri = Application.GetResourceStream(uri);
      StreamReader reader = new StreamReader(sri.Stream);
      string xml = reader.ReadToEnd();

      long id = 0;

      // create the sandwich list
      XDocument doc = XDocument.Parse(xml);
      Sandwiches = doc.Descendants("sandwich")
                      .Select(el => new Sandwich()
                      {
                        Title = el.Attribute("title").Value,
                        Id = id++,
                        Keywords = el.Descendants("keyword")
                                      .Select(l => Regex.Replace(l.Value, @"\b(\w)", m => m.Value.ToUpper()))                                      
                                      .ToList(),
                        Ingredients = el.Descendants("ingredient")
                                        .Select(l => l.Value)
                                        .ToList(),
                        Instructions = el.Descendants("instruction")
                                        .Select(l => new InstructionStep()
                                        {
                                          Text = l.Value,
                                          Step = l.ElementsBeforeSelf().Count() + 1
                                        })
                                        .ToList()

                      })
                      .ToList();

      // create the keyword list
      id = 0;
      var uniqueKeywords = Sandwiches.SelectMany(s => s.Keywords)
                                      .Distinct();
      Keywords = new List<Keyword>();
      foreach (var keyword in uniqueKeywords)
      {
        Keywords.Add(new Keyword()
        {
          Name = keyword,
          Id = id++,
          ImageUri = doc.Descendants("keywordDefs")
                        .Descendants("keyword")
                        .Where(el => el.Value.ToLower() == keyword.ToLower())
                        .Select(el => el.Attribute("url").Value)
                        .ToList()
                        .SingleOrDefault(),
          Sandwiches = Sandwiches.Where(s => s.Keywords.Contains(keyword))
                                 .ToList()
        });
      }

      // locate related sandwiches
      foreach (var sandwich in Sandwiches)
      {
        sandwich.Similar = Sandwiches.Where(s => s != sandwich)
                            .Select(s =>
                              new
                              {
                                Sandwich = s,
                                Score = KeywordCorrelation(s.Keywords, sandwich.Keywords)
                              })
                            .OrderBy(s => s.Score).Reverse()
                            .Take(5)
                            .Select(s => s.Sandwich)
                            .ToList();
      }
    }

    private double KeywordCorrelation(List<string> keywordsOne, List<string> keywordsTwo)
    {
      var commonKeywords = keywordsOne.Intersect(keywordsTwo);
      var allKeywords = keywordsOne.Union(keywordsTwo).Distinct();
      return (double)commonKeywords.Count() / (double)allKeywords.Count();
    }
  }

  public class InstructionStep
  {
    public string Text {get; set;}

    public int Step { get; set; }
  }

  public class Sandwich
  {
    public string Title { get; set; }

    public long Id { get; set; }

    public string KeywordSummary
    {
      get
      {
        return Keywords.Aggregate((k1, k2) => k1 + ", " + k2);
      }
    }

    public List<string> Keywords { get; set; }

    public List<string> Ingredients { get; set; }

    public List<InstructionStep> Instructions { get; set; }

    public List<Sandwich> Similar { get; set; }
  }

  public class Keyword
  {
    public long Id { get; set; }

    public string Name { get; set; }

    public string ImageUri { get; set; }

    public List<Sandwich> Sandwiches { get; set; }
  }
}
